import type { Schema } from "@rivet/model";

import type { PatchState, Transaction } from "@rivet/state";
import type { Node as RivetNode } from "@rivet/model";
import type { Editor } from "./editor.ts";
import type { Extension } from "./Extension.ts";
import type { Node } from "./Node.ts";
import type { Mark } from "./Mark.ts";
import type {
  Commands,
  ExtensionConfig,
  MarkConfig,
  NodeConfig,
  Selectors,
} from "@valuation/core";

export interface EditorEvents {
  beforeCreate: { editor: Editor };
  create: { editor: Editor };
  update: { editor: Editor; transaction: Transaction };
  transaction: { editor: Editor; transaction: Transaction };
  destroy: void;
}

export type AnyExtension = Extension | Node | Mark;
export type Extensions = AnyExtension[];
export interface EditorOptions {
  content: (schema: Schema) => RivetNode; //根据schema生成内容
  extensions: Extensions; //插件
  onBeforeCreate: (props: EditorEvents["beforeCreate"]) => void;
  onCreate: (props: EditorEvents["create"]) => void;
  onUpdate: (props: EditorEvents["update"]) => void;
  onTransaction: (props: EditorEvents["transaction"]) => void;
  onDestroy: (props: EditorEvents["destroy"]) => void;
  historyLimit: number; //历史记录数量
  lruMaxSize: number; //缓存数量
}

export type MaybeReturnType<T> = T extends (...args: any) => any ? ReturnType<T>
  : T;

export type AnyConfig = ExtensionConfig | NodeConfig | MarkConfig;

export type GlobalAttributes = {
  types: string[];
  attributes: {
    [key: string]: Attribute;
  };
}[];

export type Attribute = {
  default: any;
  isRequired: boolean;
};
export type Attributes = {
  [key: string]: Attribute;
};

export type ParentConfig<T> = Partial<
  {
    [P in keyof T]: Required<T>[P] extends (...args: any) => any
      ? (...args: Parameters<Required<T>[P]>) => ReturnType<Required<T>[P]>
      : T[P];
  }
>;
export type RemoveThis<T> = T extends (...args: any) => any
  ? (...args: Parameters<T>) => ReturnType<T>
  : T;

export type MaybeThisParameterType<T> = Exclude<T, Primitive> extends
  (...args: any) => any ? ThisParameterType<Exclude<T, Primitive>>
  : any;

export type Primitive =
  | null
  | undefined
  | string
  | number
  | boolean
  | symbol
  | bigint;

export type ExtensionAttribute = {
  type: string;
  name: string;
  attribute: Required<Attribute>;
};

export type JSONContent = {
  type?: string;
  attrs?: Record<string, any>;
  content: JSONContent[];
  marks?: {
    type: string;
    attrs?: Record<string, any>;
    [key: string]: any;
  }[];
  [key: string]: any;
};
export type UnionToIntersection<U> =
  (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I
    : never;
export type ValuesOf<T> = T[keyof T];

export type CommandProps = {
  editor: Editor;
  tr: Transaction;
  state: PatchState;
};

export type Command = (props: CommandProps) => void;

export type AnyCommands = Record<string, (...args: any[]) => Command>;

export type RawCommands = {
  [Item in keyof UnionCommands]: UnionCommands[Item];
};

export type UnionCommands = UnionToIntersection<
  ValuesOf<Pick<Commands, KeysWithTypeOf<Commands, {}>>>
>;

export type KeysWithTypeOf<T, Type> =
  ({ [P in keyof T]: T[P] extends Type ? P : never })[keyof T];

export type SingleCommands = {
  [Item in keyof UnionCommands]: UnionCommands[Item];
};

export type Selector = (props: any) => any;
export type SelectorItem = {
  dependency:any[],
  selector:Selector
};
export type  SelectorResult =SelectorItem|Selector;
export type AnySelectors = Record<string, (...args: any[]) => SelectorItem|Selector>;
export type RawSelectors = {
  [Item in keyof UnionSelectors]: UnionSelectors[Item];
};
export type UnionSelectors = UnionToIntersection<
  ValuesOf<Pick<Selectors, KeysWithTypeOf<Selectors, {}>>>
>;

export type SingleSelectors = {
  [Item in keyof UnionSelectors]: UnionSelectors[Item];
};
